﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

namespace GBFramework
{
    /// <summary>
    /// 游戏资源缓存管理
    /// </summary>
    public class GameSpriteCacheManager
    {

        #region 缓存管理器
        //加载完成
        Hashtable mMapResourceCache;
        //正在被加载
        List<string> mListProcessCache;
        //等待下载
        Hashtable mMapWaitDowload;

        private static GameSpriteCacheManager _instance;
        public static GameSpriteCacheManager Instance()
        {
            if (_instance == null)
            {
                _instance = new GameSpriteCacheManager();
            }
            return _instance;
        }

        public GameSpriteCacheManager()
        {
            Init();
        }

        public void Init()
        {
            mMapResourceCache = new Hashtable();
            mListProcessCache = new List<string>();
            mMapWaitDowload = new Hashtable();
        }


        int curLoadCount = 0;
        int curDowloadCount = 0;
        int curDeleteCount = 0;
        //当次最大下载次数
        private readonly static int uMaxProcessCacheCount = 100;
        public void Update()
        {
            if (mListProcessCache.Count < uMaxProcessCacheCount && mMapWaitDowload.Count > 0)
            {
                IDictionaryEnumerator em = mMapWaitDowload.GetEnumerator();
                while (em.MoveNext())
                {
                    //是否正在下载(如果正在下载就把本次加载放进等待列表中，等待对应的资源下载完成后从等待列表中将数据拿出来)
                    if (!HashProcessDowloadCache(em.Key.ToString()))
                    {
                        AddProcessDowloadCache(em.Key.ToString());

                        curLoadCount++;
                        string resPath = em.Key.ToString();
                        AppFacade.Instance.GetManager<ResourceManager>(ManagerName.Resource).LoadAllSpriteAsync(em.Key.ToString(),
                            (objectsArr, args) =>
                            {

                                curDowloadCount++;
                                string assetbundleName = args[0] as string;
                                WaitDowloadData waitDowloadData = GetWaitDowload(resPath);
                                if (null == waitDowloadData)
                                    return;
                                foreach (WaitDowloadFuncData item in waitDowloadData.lstFunc)
                                {
                                    if (item.funcSpriteCallBack != null)
                                    {
                                        if (item.isPushCache)
                                        {
                                            if (objectsArr != null)
                                                AddResourceCache(resPath, objectsArr, assetbundleName);
                                            else
                                            {
                                                AddResourceCache(resPath, new List<Object>().ToArray(), assetbundleName);
                                            }
                                        }

                                        Hashtable objArr = GetResoureCache_UnRef(resPath);
                                        item.funcSpriteCallBack(objArr, item.lstObj);
                                    }
                                }

                                RemoveWaitDowload(resPath);

                                RemoveProcessDowloadCache(resPath);

                            });
                    }

                    //当帧下载的数量超过数量下载限制，跳出本次下载
                    if (mListProcessCache.Count >= uMaxProcessCacheCount)
                        break;
                }
            }
        }

        /// <summary>
        /// 释放所有缓存资源
        /// </summary>
        public void ReleaseAllCache()
        {
            List<string> lstTemp = new List<string>();
            IDictionaryEnumerator em = mMapResourceCache.GetEnumerator();

            while (em.MoveNext())
            {
                lstTemp.Add(em.Key.ToString());
            }
            for (int i = 0; i < lstTemp.Count; i++)
            {
                string pathName = lstTemp[i];
                AssetsCacheData data = null;
                if (mMapResourceCache.ContainsKey(pathName))
                {
                    data = mMapResourceCache[pathName] as AssetsCacheData;
                }

                if (data == null) continue;

                int refCount = data.RefCount;
                for (int j = 0; j < refCount; j++)
                {
                    RemoveResourceCache(lstTemp[i]);
                }
            }
            lstTemp.Clear();
            lstTemp = null;
            mMapResourceCache.Clear();

            #region 有先后顺序关系
            ReleaseAllProcessDowload();
            ReleaseAllWaitDowloadDowload();
            #endregion
            //Resources.UnloadUnusedAssets();
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="pathName">路径名</param>
        /// <param name="assets">资源</param>
        public void AddResourceCache(string pathName, Object[] assetsArr, string assetbundleName)
        {
            if (assetsArr == null)
                return;

            if (mMapResourceCache.ContainsKey(pathName))
            {
                AssetsCacheData data = mMapResourceCache[pathName] as AssetsCacheData;
                data.resourcePathName = pathName;
                data.assetbundleName = assetbundleName;
                data.AllAssets = new Hashtable();

                int lenght = assetsArr.Length;
                for (int i = 0; i < lenght; i++)
                {
                    Sprite sprite = assetsArr[i] as Sprite;
                    if (sprite != null)
                    {
                        if (!data.AllAssets.ContainsKey(assetsArr[i].name))
                            data.AllAssets.Add(assetsArr[i].name, assetsArr[i]);
                    }
                    else
                    {
                        Texture texture = assetsArr[i] as Texture;
                        if (texture != null)
                        {
                            string key = assetsArr[i].name + "_texture";
                            if (!data.AllAssets.ContainsKey(key))
                                data.AllAssets.Add(key, assetsArr[i]);
                        }
                    }
                }
                data.RefCount++;
            }
            else
            {
                AssetsCacheData data = new AssetsCacheData();
                data.resourcePathName = pathName;
                data.assetbundleName = assetbundleName;
                data.AllAssets = new Hashtable();

                int lenght = assetsArr.Length;
                for (int i = 0; i < lenght; i++)
                {
                    Sprite sprite = assetsArr[i] as Sprite;
                    if (sprite != null)
                    {
                        if (!data.AllAssets.ContainsKey(assetsArr[i].name))
                            data.AllAssets.Add(assetsArr[i].name, assetsArr[i]);
                    }
                    else
                    {
                        Texture texture = assetsArr[i] as Texture;
                        if (texture != null)
                        {
                            string key = assetsArr[i].name + "_texture";
                            if (!data.AllAssets.ContainsKey(key))
                                data.AllAssets.Add(key, assetsArr[i]);
                        }
                    }
                }
                data.RefCount = 1;

                mMapResourceCache.Add(pathName, data);
            }
        }

        private Hashtable GetResoureCache_UnRef(string pathName)
        {
            if (mMapResourceCache.ContainsKey(pathName))
            {
                AssetsCacheData data = mMapResourceCache[pathName] as AssetsCacheData;
                if (data != null) { return data.AllAssets; }
            }

            return null;
        }

        /// <summary>
        /// 获取
        /// </summary>
        /// <param name="pathName"></param>
        /// <returns></returns>
        public Hashtable GetResourceCache(string pathName)
        {
            if (mMapResourceCache.ContainsKey(pathName))
            {
                AssetsCacheData data = mMapResourceCache[pathName] as AssetsCacheData;
                if (data != null) { data.RefCount++; return data.AllAssets; }
            }

            return null;
        }

        /// <summary>
        /// 移除
        /// </summary>
        /// <param name="pathName"></param>
        public void RemoveResourceCache(string pathName)
        {
            if (mMapResourceCache.ContainsKey(pathName))
            {
                AssetsCacheData data = mMapResourceCache[pathName] as AssetsCacheData;
                data.RefCount--;

                if (data.RefCount <= 0)
                {
                    data.RefCount = 0;
                    ReleaseResourceCache(data);
                    mMapResourceCache.Remove(pathName);
                }
            }
        }

        /// <summary>
        /// 释放缓存资源
        /// </summary>
        /// <param name="pathName"></param>
        private void ReleaseResourceCache(AssetsCacheData data)
        {
            if (data.AllAssets != null)
            {
                data.AllAssets.Clear();
                data.AllAssets = null;
                AppFacade.Instance.GetManager<ResourceManager>(ManagerName.Resource).unloadAssetName(data.assetbundleName);
                curDeleteCount++;
            }
        }
        #endregion
        //-------------------------------------------------------
        #region 正在下载
        public void AddProcessDowloadCache(string resPath)
        {
            if (!mListProcessCache.Contains(resPath))
            {
                mListProcessCache.Add(resPath);
            }
        }

        public bool HashProcessDowloadCache(string resPath)
        {
            return mListProcessCache.Contains(resPath);
        }

        public void RemoveProcessDowloadCache(string resPath)
        {
            mListProcessCache.Remove(resPath);
        }

        public void ReleaseAllProcessDowload()
        {
            for (int i = 0; i < mListProcessCache.Count; i++)
            {
                string resPath = mListProcessCache[i];

                AssetBundleManager.UnloadAssetBundle(resPath, true);

                RemoveWaitDowload(resPath);

                //RemoveProcessDowloadCache(resPath);
            }
            mListProcessCache.Clear();
        }
        #endregion
        //--------------------------------------------------------
        #region 等待下载
        /// <summary>
        /// 等待下载 (不对外开放，要使用请调用uGUI_LuaManager  LoadSpriteAsync_UnHide(Image image, string path, LuaFunction func) LoadSpriteAsync_UnHide(Image image, string path))
        /// 或是自己写一下方法，记的要处理好Image为空的情况
        /// </summary>
        /// <param name="resPath">下载资源路径</param>
        /// <param name="lstObj">传递进来的参数，用于下载完成回调</param>
        /// <param name="func">回调函数</param>
        /// <param name="isPushCache">下载的资源是否进入到缓存池中</param>
        public void AddWaitDowload(string resPath, List<object> lstObj, DowloadAllSpriteCallBack func, bool isPushCache = true)
        {
            Hashtable objArr = GetResourceCache(resPath);
            if (objArr != null)
            {
                if (func != null)
                {
                    func(objArr, lstObj);
                }
                return;
            }
            if (mMapWaitDowload.ContainsKey(resPath))
            {
                WaitDowloadData data = mMapWaitDowload[resPath] as WaitDowloadData;
                WaitDowloadFuncData funcData = new WaitDowloadFuncData();
                funcData.lstObj = lstObj;
                funcData.funcSpriteCallBack = func;
                funcData.isPushCache = isPushCache;

                data.lstFunc.Add(funcData);
            }
            else
            {
                WaitDowloadData data = new WaitDowloadData();
                WaitDowloadFuncData funcData = new WaitDowloadFuncData();
                funcData.lstObj = lstObj;
                funcData.funcSpriteCallBack = func;
                funcData.isPushCache = isPushCache;

                data.lstFunc.Add(funcData);

                mMapWaitDowload.Add(resPath, data);
            }
        }

        public WaitDowloadData GetWaitDowload(string resPath)
        {
            if (mMapWaitDowload.ContainsKey(resPath))
                return mMapWaitDowload[resPath] as WaitDowloadData;

            return null;
        }

        public bool HashWaitDowload(string resPath)
        {
            return mMapWaitDowload.ContainsKey(resPath);
        }

        public void RemoveWaitDowload(string resPath)
        {
            if (mMapWaitDowload.ContainsKey(resPath))
            {
                WaitDowloadData data = mMapWaitDowload[resPath] as WaitDowloadData;
                for (int i = 0; i < data.lstFunc.Count; i++)
                {
                    WaitDowloadFuncData funcData = data.lstFunc[i];
                    funcData.funcSpriteCallBack = null;
                    if (null != funcData.lstObj)
                        funcData.lstObj.Clear();
                }

                mMapWaitDowload.Remove(resPath);
            }
        }

        public void ReleaseAllWaitDowloadDowload()
        {
            IDictionaryEnumerator em = mMapWaitDowload.GetEnumerator();
            while (em.MoveNext())
            {
                WaitDowloadData data = em.Value as WaitDowloadData;
                for (int i = 0; i < data.lstFunc.Count; i++)
                {
                    WaitDowloadFuncData funcData = data.lstFunc[i];
                    funcData.funcSpriteCallBack = null;
                    if (null != funcData.lstObj)
                    {
                        funcData.lstObj.Clear();
                        funcData.lstObj = null;
                    }
                }
            }
            mMapWaitDowload.Clear();
        }
        #endregion
    }
}